home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / NRCMD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  37.8 KB  |  1,531 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by G1EMM, PA0GRI and WG7J */
  6.  
  7. #include "global.h"
  8. #ifdef NETROM
  9. #include "ctype.h"
  10. #include "commands.h"
  11. #include "mbuf.h"
  12. #include "ax25.h"
  13. #include "mailbox.h"
  14. #include "netrom.h"
  15. #include "pktdrvr.h"
  16. #include "files.h"
  17. #ifndef MSDOS
  18. #include "session.h"
  19. #endif
  20.  
  21. #if !defined(_lint)
  22. static char rcsid[] OPTIONAL = "$Id: nrcmd.c,v 1.22 1997/09/07 21:18:28 root Exp root $";
  23. #endif
  24.  
  25. /*lint -esym(534,pax25) */
  26. static int Nr_hidden = 1;
  27. static unsigned Nr_sorttype = 1;
  28. char Nr4user[AXALEN];
  29. extern unsigned Nr_sorttype;
  30. extern int Nr_derate;
  31. extern int Nr_promisc;
  32. extern unsigned Nr_timertype;
  33.  
  34.  
  35. const char *Nr4states[] =
  36. {
  37.     "Disconnected",
  38.     "Conn Pending",
  39.     "Connected",
  40.     "Disc Pending",
  41.     "Listening"
  42. };
  43.  
  44. const char *Nr4reasons[] =
  45. {
  46.     "Normal",
  47.     "By Peer",
  48.     "Timeout",
  49.     "Reset",
  50.     "Refused"
  51. };
  52.  
  53. static void nodetickproc (int, void *, void *);
  54. static int dobcnodes (int argc, char *argv[], void *p);
  55. static int dobcpoll (int argc, char *argv[], void *p);
  56. static int dointerface (int argc, char *argv[], void *p);
  57. static int donfadd (int argc, char *argv[], void *p);
  58. static int donfdrop (int argc, char *argv[], void *p);
  59. static int donfdump (void);
  60. static int donfmode (int argc, char *argv[], void *p);
  61. static int donodefilter (int argc, char *argv[], void *p);
  62. static int donodetimer (int argc, char *argv[], void *p);
  63. static int donracktime (int argc, char *argv[], void *p);
  64. static int donrmycall (int argc, char *argv[], void *p);
  65. static int donrchoketime (int argc, char *argv[], void *p);
  66. static int donrconnect (int argc, char *argv[], void *p);
  67. static int donrirtt (int argc, char *argv[], void *p);
  68. static int donrkick (int argc, char *argv[], void *p);
  69. static int dorouteadd (int argc, char *argv[], void *p);
  70. static int doroutedrop (int argc, char *argv[], void *p);
  71. static int donrqlimit (int argc, char *argv[], void *p);
  72. static int donrreset (int argc, char *argv[], void *p);
  73. static int donrretries (int argc, char *argv[], void *p);
  74. int donrroute (int argc, char *argv[], void *p);
  75. int donrstatus (int argc, char *argv[], void *p);
  76. static int donrsave (int argc, char *argv[], void *p);
  77. static int donrload (int argc, char *argv[], void *p);
  78. static int donrttl (int argc, char *argv[], void *p);
  79. static int donruser (int argc, char *argv[], void *p);
  80. static int donrwindow (int argc, char *argv[], void *p);
  81. void doobsotick (void);
  82. static int doobsotimer (int argc, char *argv[], void *p);
  83. static int dominquality (int argc, char *argv[], void *p);
  84. static int donrtype (int argc, char *argv[], void *p);
  85. static int donrpromisc (int argc, char *argv[], void *p);
  86. static int donrderate (int argc, char *argv[], void *p);
  87. static int doroutesort (int argc, char *argv[], void *p);
  88. static int donrhidden (int argc, char *argv[], void *p);
  89. static void doallinfo (void);
  90. static struct iface *FindNrIface (char *name);
  91.  
  92. int donrneighbour (int argc, char *argv[], void *p);
  93.  
  94. extern int donr4tdisc (int argc, char *argv[], void *p);
  95. extern struct nr_bind *find_best (struct nr_bind * list, unsigned obso);
  96. extern void nrresetlinks (struct nrroute_tab *rp);
  97.  
  98. static struct cmds Nrcmds[] =
  99. {
  100.     { "acktime",     donracktime,    0,    0, NULLCHAR },
  101.     { "alias",     donralias,    0,    0, NULLCHAR },
  102.     { "bcnodes",     dobcnodes,    0,    2, "netrom bcnodes <iface>" },
  103.     { "bcpoll",     dobcpoll,    0,    2, "netrom bcpoll <iface>" },
  104. #ifdef ALLSESSIONS
  105.     { "connect",     donrconnect,    1024,    2, "netrom connect <node>" },
  106. #endif
  107.     { "call",     donrmycall,    0,    0, NULLCHAR },
  108.     { "choketime",     donrchoketime,    0,    0, NULLCHAR },
  109.     { "derate",     donrderate,    0,    0, NULLCHAR },
  110.     { "hidden",     donrhidden,    0,    0, NULLCHAR },
  111.     { "interface",     dointerface,    0,    0, NULLCHAR },
  112.     { "irtt",     donrirtt,    0,    0, NULLCHAR },
  113.     { "kick",     donrkick,    0,    2, "netrom kick <&nrcb>" },
  114.     { "load",     donrload,    0,    0, NULLCHAR },
  115.     { "minquality",     dominquality,    0,    0, NULLCHAR },
  116.     { "neighbour",     donrneighbour,    0,    0, NULLCHAR },
  117.     { "nodefilter",     donodefilter,    0,    0, NULLCHAR },
  118.     { "nodetimer",     donodetimer,    0,    0, NULLCHAR },
  119.     { "obsotimer",     doobsotimer,    0,    0, NULLCHAR },
  120.     { "promiscuous", donrpromisc,    0,    0, NULLCHAR },
  121.     { "qlimit",     donrqlimit,    0,    0, NULLCHAR },
  122.     { "route",     donrroute,    0,    0, NULLCHAR },
  123.     { "reset",     donrreset,    0,    2, "netrom reset <&nrcb>" },
  124.     { "retries",     donrretries,    0,    0, NULLCHAR },
  125.     { "status",     donrstatus,    0,    0, NULLCHAR },
  126.     { "save",     donrsave,    0,    0, NULLCHAR },
  127. #if defined(ALLSESSIONS) && defined(ALLSERV)
  128.     { "split",     donrconnect,    1024,    2, "netrom split <node>" },
  129. #endif
  130.     { "timertype",     donrtype,    0,    0, NULLCHAR },
  131.     { "ttl",     donrttl,    0,    0, NULLCHAR },
  132. #ifdef NR4TDISC
  133.     { "tdisc",     donr4tdisc,    0,    0, NULLCHAR },
  134. #endif
  135.     { "user",     donruser,    0,    0, NULLCHAR },
  136.     { "window",     donrwindow,    0,    0, NULLCHAR },
  137.     { NULLCHAR,     NULL,        0,    0, NULLCHAR }
  138. };
  139.  
  140.  
  141. struct timer Nodetimer;        /* timer for nodes broadcasts */
  142. struct timer Obsotimer;        /* timer for aging routes */
  143.  
  144.  
  145. /* Command multiplexer */
  146. int
  147. donetrom (int argc, char *argv[], void *p)
  148. {
  149.     return subcmd (Nrcmds, argc, argv, p);
  150. }
  151.  
  152.  
  153. static struct cmds Routecmds[] =
  154. {
  155.     { "add",    dorouteadd,    0, 6, "netrom route add <alias> <destination> <interface> <quality> <neighbor>" },
  156.     { "drop",    doroutedrop,    0, 4, "netrom route drop <destination> <neighbor> <interface>" },
  157.     { "info",    dorouteinfo,    0, 0, NULLCHAR },
  158.     { "sort",    doroutesort,    0, 1, NULLCHAR },
  159.     { NULLCHAR,    NULL,        0, 0, NULLCHAR }
  160. };
  161.  
  162.  
  163. /* Route command multiplexer */
  164. int
  165. donrroute (int argc, char *argv[], void *p)
  166. {
  167.     if (argc < 2) {
  168.         (void) doroutedump ();
  169.         return 0;
  170.     }
  171.     return subcmd (Routecmds, argc, argv, p);
  172. }
  173.  
  174.  
  175. /* Code to sort Netrom node listing
  176.  * D. Crompton  2/92
  177.  * Dump a list of known netrom routes in
  178.  * sorted order determined by sort
  179.  * flag - default = sort by alias
  180.  */
  181.  
  182. int
  183. doroutedump ()
  184. {
  185. register struct nrroute_tab *rp;
  186. register int i, j, k, column;
  187. char buf[17];
  188. char *cp, *temp;
  189.  
  190.     column = 1;
  191.  
  192.     for (i = 0, j = 0; i < NRNUMCHAINS; i++)
  193.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; j++, rp = rp->next) ;
  194.  
  195. #define RTSIZE 17
  196.  
  197.     if (j) {
  198.         /* Allocate maximum size */
  199.         temp = mallocw ((unsigned) j * RTSIZE);
  200.  
  201.         for (i = 0, j = 0, k = 0; i < NRNUMCHAINS; i++)
  202.             for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  203.                 if (!Nr_hidden && *rp->alias == '#')
  204.                     continue;
  205.                 if (Nr_sorttype) {
  206.                     strncpy (buf, rp->alias, 17);
  207.                     /* remove trailing spaces */
  208.                     if ((cp = strchr (buf, ' ')) == NULLCHAR)
  209.                         cp = &buf[strlen (buf)];
  210.                     if (cp != buf)    /* don't include colon for null alias */
  211.                         *cp++ = ':';
  212.                     pax25 (cp, rp->call);
  213.                 } else {
  214.                     pax25 (buf, rp->call);
  215.                     cp = &buf[strlen (buf)];
  216.                     *cp++ = ':';
  217.                     strcpy (cp, rp->alias);
  218.                 }
  219.                 sprintf (&temp[k], "%-16.16s", buf);
  220.                 k += RTSIZE;
  221.                 j++;    /* number actually shown */
  222.             }
  223.  
  224.         qsort (temp, (size_t) j, RTSIZE, (int (*)(const void *, const void *)) strcmp);
  225.  
  226.         for (i = 0, k = 0; i < j; i++, k += RTSIZE) {
  227.             tprintf ("%-16s  ", &temp[k]);
  228.             if (column++ == 4) {
  229.                 if (tputc ('\n') == EOF) {
  230.                     free (temp);
  231.                     return 0;
  232.                 }
  233.                 column = 1;
  234.             }
  235.         }
  236.  
  237.         if (column != 1)
  238.             tputc ('\n');
  239.         free (temp);
  240.     }
  241.     return 0;
  242. }
  243.  
  244.  
  245. /* netrom Route Dump Sort - ALIAS or CALL first */
  246. static int
  247. doroutesort (int argc, char *argv[], void *p OPTIONAL)
  248. {
  249.     if (argc < 2) {
  250.         tprintf ("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call");
  251.         return 0;
  252.     }
  253.     switch (argv[1][0]) {
  254.         case 'A':
  255.         case 'a':
  256.             Nr_sorttype = 1;
  257.             break;
  258.         case 'C':
  259.         case 'c':
  260.             Nr_sorttype = 0;
  261.             break;
  262.         default:
  263.             tputs ("usage: netrom sort [alias|call]\n");
  264.             return -1;
  265.     }
  266.  
  267.     return 0;
  268. }
  269.  
  270.  
  271. /* Print detailed information on  ALL routes  (sorted) */
  272. /*  D. Crompton */
  273. static void
  274. doallinfo ()
  275. {
  276. register struct nrroute_tab *rp;
  277. register struct nr_bind *bp;
  278. register struct nrnbr_tab *np;
  279. char neighbor[AXBUF];
  280. char buf[17];
  281. char *cp, *temp;
  282. int i, j, k, flow_tmp;
  283.  
  284.     flow_tmp = Current->flowmode;
  285.     Current->flowmode = 1;
  286.  
  287.     for (i = 0, j = 0; i < NRNUMCHAINS; i++)
  288.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  289.             for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next, j++) ;
  290.  
  291. #define STRSIZE 72
  292.  
  293.     if (j) {
  294.  
  295.         temp = mallocw ((unsigned) j * STRSIZE);
  296.  
  297.         for (i = 0, k = 0; i < NRNUMCHAINS; i++)
  298.             for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  299.                 for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next, k += STRSIZE) {
  300.                     np = bp->via;
  301.                     if (Nr_sorttype) {
  302.  
  303.                         strncpy (buf, rp->alias, 17);
  304.                         if ((cp = strchr (buf, ' ')) == NULLCHAR)
  305.                             cp = &buf[strlen (buf)];
  306.                         if (cp != buf)
  307.                             *cp++ = ':';
  308.                         pax25 (cp, rp->call);
  309.  
  310.                     } else {
  311.  
  312.                         pax25 (buf, rp->call);
  313.                         cp = &buf[strlen (buf)];
  314.                         *cp++ = ':';
  315.                         strcpy (cp, rp->alias);
  316.  
  317.                     }
  318.  
  319.                     sprintf (&temp[k], "%-16s %3d %3d %-8s %-9s %c\n", buf,
  320.                          bp->quality, bp->obsocnt,
  321.                          np->iface->name,
  322.                          pax25 (neighbor, np->call),
  323.                       (bp->flags & NRB_PERMANENT ? 'P' :
  324.                        bp->flags & NRB_RECORDED ? 'R' : 'B'));
  325.  
  326.                 }
  327.         qsort (temp, (size_t) j, STRSIZE, (int (*)(const void *, const void *)) strcmp);
  328.  
  329.         for (i = 0, k = 0; i < j; i++, k += STRSIZE)
  330.             if (tputs (&temp[k]) == EOF)
  331.                 break;
  332.         free (temp);
  333.         Current->flowmode = flow_tmp;
  334.     }
  335. }
  336.  
  337.  
  338. /* Find the interface, and check if it is active for netrom */
  339. static struct iface *
  340. FindNrIface (char *name)
  341. {
  342. struct iface *ifp;
  343.  
  344.     if ((ifp = if_lookup (name)) == NULLIF) {
  345.         tprintf (Badinterface, name);
  346.         return NULLIF;
  347.     }
  348.     if (!(ifp->flags & IS_NR_IFACE)) {
  349.         tprintf ("%s is not active for netrom\n", name);
  350.         return NULLIF;
  351.     }
  352.     return ifp;
  353. }
  354.  
  355.  
  356. /* print detailed information on an individual route
  357.  * Shows alias as well - WG7J
  358.  */
  359. int
  360. dorouteinfo (int argc, char *argv[], void *p OPTIONAL)
  361. {
  362. char *cp;
  363. register struct nrroute_tab *rp;
  364. register struct nrroute_tab *npp;
  365. struct nr_bind *bp;
  366. struct nrnbr_tab *np;
  367. char destbuf[AXBUF];
  368. char neighbor[AXBUF];
  369. char alias[AXALEN];
  370. char buf[AXALEN];
  371. char nb_alias[AXALEN];
  372. int print_header = 1;
  373. int16 rhash;
  374.  
  375.     if (argc == 1) {
  376.         doallinfo ();
  377.         return 0;
  378.     }
  379.     (void) putalias (alias, argv[1], 0);
  380.     (void) strupr (argv[1]);    /*make sure it's upper case*/
  381.     if ((rp = find_nrboth (alias, argv[1])) == NULLNRRTAB) {
  382.         /*no such call or node alias*/
  383.         tputs ("no such node\n\n");
  384.         return 0;
  385.     }
  386.     /*copy the real alias*/
  387.     strncpy (buf, rp->alias, AXALEN);
  388.     if ((cp = strchr (buf, ' ')) != NULLCHAR)
  389.         *cp = '\0';
  390.  
  391.     for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  392.         np = bp->via;
  393.         /* now we have to find the alias of the neighbour used
  394.          * so we can print that as well!
  395.          */
  396.         rhash = nrhash (np->call);
  397.         for (npp = Nrroute_tab[rhash]; npp != NULLNRRTAB; npp = npp->next)
  398.             if (addreq (npp->call, np->call))
  399.                 break;
  400.         if (npp == NULLNRRTAB)
  401.             continue;
  402.         /* found, now remove trailing spaces */
  403.         strcpy (nb_alias, npp->alias);
  404.         if ((cp = strchr (nb_alias, ' ')) != NULLCHAR)
  405.             *cp = '\0';
  406.         if (print_header) {
  407.             print_header = 0;
  408.             tputs ("      Node          Neighbour       Port  PQual Obsocnt Type\n");
  409.             tprintf ("%6s:%-9s  ", buf, pax25 (destbuf, rp->call));
  410.         } else
  411.             tputs ("                  ");
  412.         tprintf ("%6s:%-9s  %-5s  %3d      %d     %c\n",
  413.              nb_alias, pax25 (neighbor, np->call),
  414.              np->iface->name,
  415.              bp->quality, bp->obsocnt,
  416.              bp->flags & NRB_PERMANENT ? 'P' : \
  417.              (bp->flags & NRB_RECORDED ? 'R' : 'B'));
  418.     }
  419.     tputc ('\n');
  420.     return 0;
  421. }
  422.  
  423.  
  424. int
  425. donrneighbour (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  426. {
  427. int i, printheader = 1;
  428. struct nrnbr_tab *np;
  429. struct nrroute_tab *rp;
  430. struct nr_bind *thebind;
  431. int16 rhash;
  432. int justused;
  433. char tmp[AXBUF];
  434. char alias[AXALEN];
  435. char *cp;
  436. int quality = 0;
  437. int obsocnt = 0;
  438.  
  439.     for (i = 0; i < NRNUMCHAINS; i++)    /*loop through all chains of neighbours*/
  440.         for (np = Nrnbr_tab[i]; np != NULLNTAB; np = np->next) {
  441.             /* If the interface is hidden, then do not show the route */
  442.             /*
  443.                 if(np->iface->flags & HIDE_PORT && Curproc->input != Command->input)
  444.                 continue;
  445.              */
  446.             if (printheader) {
  447.                 tputs ("Routes :\n   Neighbour       Port  PQual Obsocnt Dest\n");
  448.                 printheader = 0;
  449.             }
  450.             /* has this one been used recently ? */
  451.             if ((secclock () - np->lastsent) < 60)
  452.                 justused = 1;
  453.             else
  454.                 justused = 0;
  455.  
  456.             /* now we have to find the alias of this neighbour
  457.              * so we can print that as well!
  458.              */
  459.             rhash = nrhash (np->call);
  460.             for (rp = Nrroute_tab[rhash]; rp != NULLNRRTAB; rp = rp->next)
  461.                 if (addreq (rp->call, np->call))
  462.                     break;
  463.  
  464.             if (rp != NULLNRRTAB) {
  465.                 /* found, now remove trailing spaces */
  466.                 strcpy (alias, rp->alias);
  467.                 if ((cp = strchr (alias, ' ')) != NULLCHAR)
  468.                     *cp = '\0';
  469.                 /*find the quality for this neighbour*/
  470.                 thebind = find_best (rp->routes, 1);
  471.                 if (thebind) {
  472.                     quality = (int) thebind->quality;
  473.                     obsocnt = (int) thebind->obsocnt;
  474.                 } else    /* this shouldn't happen */
  475.                     quality = obsocnt = 0;
  476.             } else
  477.                 strcpy (alias, "##temp");
  478.  
  479.             /* print it all out */
  480.             tprintf ("%s %6s:%-9s  %-5s %4d     %1d    %3d\n",
  481.                  (justused) ? ">" : " ",
  482.                  alias, pax25 (tmp, np->call),
  483.                  np->iface->name,
  484.                  quality, obsocnt, np->refcnt);
  485.         }
  486.     if (!printheader)
  487.         tputc ('\n');
  488.     return 0;
  489. }
  490.  
  491.  
  492. /* define the netrom call,
  493.  * this simply changes the interface linkaddress!
  494.  * but is a little easier to use...
  495.  */
  496. static int
  497. donrmycall (int argc, char *argv[], void *p OPTIONAL)
  498. {
  499. char tmp[AXBUF];
  500.  
  501.     if (Nr_iface == NULLIF) {
  502.         tputs ("Attach netrom interface first\n");
  503.         return 1;
  504.     }
  505.     if (argc < 2) {
  506.         if (Nr_iface->hwaddr == NULLCHAR)
  507.             tputs ("not set\n");
  508.         else
  509.             tprintf ("%s\n", pax25 (tmp, Nr_iface->hwaddr));
  510.     } else {
  511.         if (strlen (argv[1]) > (AXBUF - 1)) {
  512.             tputs ("too long\n");
  513.             return 1;
  514.         }
  515.         if (Nr_iface->hwaddr != NULLCHAR)
  516.             free (Nr_iface->hwaddr);
  517.         Nr_iface->hwaddr = mallocw ((unsigned) Nr_iface->iftype->hwalen);
  518.         (void) (*Nr_iface->iftype->scan) (Nr_iface->hwaddr, argv[1]);
  519. #ifdef MAILBOX
  520.         setmbnrid ();
  521. #endif
  522.     }
  523.     return 0;
  524. }
  525.  
  526.  
  527. /* make an interface available to net/rom */
  528. /* arguments are:
  529.  * argv[0] - "interface"
  530.  * argv[1] - "iface" , the interface name
  531.  * argv[2] - "quality", the interface broadcast quality
  532.  * argv[3] - "n" or "v", to override the default (verbose)
  533.  *            n = never broadcast verbose
  534.  *            v = always broadcast verbose
  535.  */
  536. static
  537. int
  538. dointerface (int argc, char *argv[], void *p OPTIONAL)
  539. {
  540. register struct iface *ifp;
  541. int i, mtu;
  542.  
  543.     if (Nr_iface == NULLIF) {
  544.         tputs ("Attach netrom interface first\n");
  545.         return 1;
  546.     }
  547.     if (argc < 3) {
  548.         i = 0;
  549.         for (ifp = Ifaces; ifp; ifp = ifp->next) {
  550.             if (ifp->flags & IS_NR_IFACE) {
  551.                 if (!i) {
  552.                     i = 1;
  553.                     tputs ("Iface  Qual Verbose\n");
  554.                 }
  555.                 tprintf ("%-6s %-3d     %c\n",
  556.                      ifp->name, ifp->quality,
  557.                      (ifp->flags & NR_VERBOSE) ? 'Y' : 'N');
  558.             }
  559.         }
  560.         return 0;
  561.     }
  562.     if ((ifp = if_lookup (argv[1])) == NULLIF) {
  563.         tprintf (Badinterface, argv[1]);
  564.         return 1;
  565.     }
  566.     if (ifp->type != CL_AX25) {
  567.         tprintf ("Interface %s is not NETROM compatible\n", argv[1]);
  568.         return 1;
  569.     }
  570.  
  571.     if (!strcasecmp (argv[2], "off"))    {
  572.         ifp->flags &= ~IS_NR_IFACE;
  573.         return 0;
  574.     }
  575.  
  576.     /* activate the interface */
  577.     ifp->flags |= IS_NR_IFACE;
  578.  
  579.     /* set quality */
  580.     if ((ifp->quality = atoi (argv[2])) > 255)    /*Maximum quality possible*/
  581.         ifp->quality = 255;
  582.     /*check to see if quality is not 0 */
  583.     if (ifp->quality <= 0)
  584.         ifp->quality = 1;
  585.  
  586.     /* default is none-verbose */
  587.     ifp->flags &= ~NR_VERBOSE;
  588.     if (argc > 3)
  589.         if (*argv[3] == 'v')
  590.             ifp->flags |= NR_VERBOSE;
  591.  
  592.     /* Check, and set the NETROM MTU - WG7J */
  593.     if ((mtu = ifp->ax25->paclen - 20) < Nr_iface->mtu)
  594.         Nr_iface->mtu = (int16) mtu;
  595.  
  596.     /* Poll other nodes on this interface */
  597.     nr_bcpoll (ifp);
  598.  
  599.     return 0;
  600. }
  601.  
  602.  
  603. /* convert a null-terminated alias name to a blank-filled, upcased */
  604. /* version.  Return -1 on failure. */
  605. int
  606. putalias (register char *to, register char *from, int complain)
  607. {
  608. int len, i;
  609.  
  610.     if (!to || !from) {
  611.         if (complain)
  612.             tputs ("alias or call invalid\n");
  613.         return -1;
  614.     }
  615.     if ((len = (int) strlen (from)) > ALEN) {
  616.         if (complain)
  617.             tputs ("alias too long - six characters max\n");
  618.         return -1;
  619.     }
  620.     for (i = 0; i < ALEN; i++) {
  621.         if (i < len) {
  622.             if (islower (*from))
  623.                 *to++ = (char) toupper (*from++);
  624.             else
  625.                 *to++ = *from++;
  626.         } else
  627.             *to++ = ' ';
  628.     }
  629.  
  630.     *to = '\0';
  631.     return 0;
  632. }
  633.  
  634.  
  635. /* Add a route */
  636. static int
  637. dorouteadd (int argc, char *argv[], void *p OPTIONAL)
  638. {
  639. char alias[AXALEN];
  640. char dest[AXALEN];
  641. unsigned quality;
  642. char neighbor[AXALEN];
  643. struct iface *ifp;
  644. int naddr;
  645.  
  646.     /* format alias (putalias prints error message if necessary) */
  647.     if (putalias (alias, argv[1], 1) == -1)
  648.         return -1;
  649.  
  650.     /* format destination callsign */
  651.     if (setcall (dest, argv[2]) == -1) {
  652.         tputs ("bad destination callsign\n");
  653.         return -1;
  654.     }
  655.     /* find interface */
  656.     if ((ifp = FindNrIface (argv[3])) == NULLIF) {
  657.         return -1;
  658.     }
  659.     /* get and check quality value */
  660.     if ((quality = (unsigned int) atoi (argv[4])) > 255) {
  661.         tputs ("maximum route quality is 255\n");
  662.         return -1;
  663.     }
  664.     /* Change from 871225 -- no digis in net/rom table */
  665.     naddr = argc - 5;
  666.     if (naddr > 1) {
  667.         tputs ("Use the ax25 route command to specify digipeaters\n");
  668.         return -1;
  669.     }
  670.     /* format neighbor address string */
  671.     (void) setcall (neighbor, argv[5]);
  672.  
  673.     return nr_routeadd (alias, dest, ifp, quality, neighbor, 1, 0);
  674. }
  675.  
  676.  
  677. /* drop a route */
  678. static int
  679. doroutedrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  680. {
  681. char dest[AXALEN], neighbor[AXALEN];
  682. struct iface *ifp;
  683.  
  684.     /* format destination and neighbor callsigns */
  685.     if (setcall (dest, argv[1]) == -1) {
  686.         tputs ("bad destination callsign\n");
  687.         return -1;
  688.     }
  689.     if (setcall (neighbor, argv[2]) == -1) {
  690.         tputs ("bad neighbor callsign\n");
  691.         return -1;
  692.     }
  693.     /* find interface */
  694.     if ((ifp = FindNrIface (argv[3])) == NULLIF)
  695.         return -1;
  696.  
  697.     return nr_routedrop (dest, neighbor, ifp);
  698. }
  699.  
  700.  
  701. /* Broadcast nodes list on named interface. */
  702. static int
  703. dobcnodes (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  704. {
  705. struct iface *ifp;
  706.  
  707.     /* find interface */
  708.     if ((ifp = FindNrIface (argv[1])) == NULLIF)
  709.         return -1;
  710.  
  711.     nr_bcnodes (ifp);
  712.     return 0;
  713. }
  714.  
  715.  
  716. /* Poll nodes for routes on named interface. - WG7J */
  717. static int
  718. dobcpoll (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  719. {
  720. struct iface *ifp;
  721.  
  722.     /* find interface */
  723.     if ((ifp = FindNrIface (argv[1])) == NULLIF)
  724.         return -1;
  725.  
  726.     nr_bcpoll (ifp);
  727.     return 0;
  728. }
  729.  
  730.  
  731. /* Set outbound node broadcast interval */
  732. static int
  733. donodetimer (int argc, char *argv[], void *p OPTIONAL)
  734. {
  735.     if (argc < 2) {
  736.         tprintf ("Nodetimer %lu/%lu seconds\n",
  737.              read_timer (&Nodetimer) / 1000L,
  738.              dur_timer (&Nodetimer) / 1000L);
  739.         return 0;
  740.     }
  741.     stop_timer (&Nodetimer);/* in case it's already running */
  742.     Nodetimer.func = (void (*)(void *)) donodetick;    /* what to call on timeout */
  743.     Nodetimer.arg = NULLCHAR;    /* dummy value */
  744.     set_timer (&Nodetimer, atoi (argv[1]) * 1000L);    /* set timer duration */
  745.     start_detached_timer (&Nodetimer);    /* and fire it up */
  746.     return 0;
  747. }
  748.  
  749.  
  750. /* nodetickproc is the old donodetick.   But, since it can call kpause, which is
  751.  * very very bad for timer functions :-( this has been converted to a server.
  752.  */
  753. void
  754. donodetick ()
  755. {
  756.     if (newproc ("NETROM broadcast", 2048, nodetickproc, 0, NULL, NULL, 0) == NULLPROC)
  757.         log (-1, "Couldn't start NETROM broadcast process");
  758.  
  759. }
  760.  
  761. static void
  762. nodetickproc (int i OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
  763. {
  764. struct iface *ifp;
  765.  
  766.     for (ifp = Ifaces; ifp; ifp = ifp->next) {
  767.         if (ifp->flags & IS_NR_IFACE)
  768.             nr_bcnodes (ifp);
  769.         /* we want to delay after VERBOSE NETROM interfaces (except the last one) */
  770.         if ((ifp->flags & NR_VERBOSE) && (ifp->next))
  771.             (void) kpause (5000);    /* this is needed to keep things hopping */
  772.     }
  773.  
  774.     /* Restart timer */
  775.     start_detached_timer (&Nodetimer);
  776. }
  777.  
  778.  
  779. /* Set timer for aging routes */
  780. static int
  781. doobsotimer (int argc, char *argv[], void *p OPTIONAL)
  782. {
  783.     if (argc < 2) {
  784.         tprintf ("Obsotimer %lu/%lu seconds\n",
  785.              read_timer (&Obsotimer) / 1000L,
  786.              dur_timer (&Obsotimer) / 1000L);
  787.         return 0;
  788.     }
  789.     stop_timer (&Obsotimer);/* just in case it's already running */
  790.     Obsotimer.func = (void (*)(void *)) doobsotick;    /* what to call on timeout */
  791.     Obsotimer.arg = NULLCHAR;    /* dummy value */
  792.     set_timer (&Obsotimer, atoi (argv[1]) * 1000L);    /* set timer duration */
  793.     start_detached_timer (&Obsotimer);    /* and fire it up */
  794.     return 0;
  795. }
  796.  
  797.  
  798. /* Go through the routing table, reducing the obsolescence count of
  799.  * non-permanent routes, and purging them if the count reaches 0
  800.  */
  801. void
  802. doobsotick ()
  803. {
  804. register struct nrnbr_tab *np;
  805. register struct nrroute_tab *rp, *rpnext;
  806. register struct nr_bind *bp, *bpnext;
  807. int i;
  808.  
  809.     for (i = 0; i < NRNUMCHAINS; i++) {
  810.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rpnext) {
  811.             rpnext = rp->next;    /* save in case we free this route */
  812.             /* Check all bindings for this route */
  813.             for (bp = rp->routes; bp != NULLNRBIND; bp = bpnext) {
  814.                 bpnext = bp->next;    /* in case we free this binding */
  815.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  816.                     continue;
  817.                 if (--bp->obsocnt == 0) {    /* time's up! */
  818.                     if (bp->next != NULLNRBIND)
  819.                         bp->next->prev = bp->prev;
  820.                     if (bp->prev != NULLNRBIND)
  821.                         bp->prev->next = bp->next;
  822.                     else
  823.                         rp->routes = bp->next;
  824.                     rp->num_routes--;    /* one less binding */
  825.                     np = bp->via;    /* find the neighbor */
  826.                     free ((char *) bp);    /* now we can free the bind */
  827.                     /* Check to see if we can free the neighbor */
  828.                     if (--np->refcnt == 0) {
  829.                         if (np->next != NULLNTAB)
  830.                             np->next->prev = np->prev;
  831.                         if (np->prev != NULLNTAB)
  832.                             np->prev->next = np->next;
  833.                         else {
  834.                             Nrnbr_tab[nrhash (np->call)] = np->next;
  835.                         }
  836.                         free ((char *) np);    /* free the storage */
  837.                     }
  838.                 }
  839.             }
  840.             if (rp->num_routes == 0) {    /* did we free them all? */
  841.                 if (rp->next != NULLNRRTAB)
  842.                     rp->next->prev = rp->prev;
  843.                 if (rp->prev != NULLNRRTAB)
  844.                     rp->prev->next = rp->next;
  845.                 else
  846.                     Nrroute_tab[i] = rp->next;
  847.                 /* No more routes left !
  848.                  * We should close/reset any netrom connections
  849.                  * still idling for this route ! - WG7J
  850.                  */
  851.                 nrresetlinks (rp);
  852.                 free ((char *) rp);
  853.             }
  854.         }
  855.     }
  856.  
  857.     start_detached_timer (&Obsotimer);
  858. }
  859.  
  860.  
  861. static struct cmds Nfcmds[] =
  862. {
  863.     { "add",    donfadd,            0, 3, "netrom nodefilter add <neighbor> <interface> [quality]" },
  864.     { "drop",    donfdrop,            0, 3, "netrom nodefilter drop <neighbor> <interface>" },
  865.     { "mode",    donfmode,            0, 0, NULLCHAR },
  866.     { NULLCHAR,    NULLFP ((int, char **, void *)),0, 0, "nodefilter subcommands: add drop mode" }
  867. };
  868.  
  869.  
  870. /* nodefilter command multiplexer */
  871. static int
  872. donodefilter (int argc, char *argv[], void *p)
  873. {
  874.     if (argc < 2) {
  875.         (void) donfdump ();
  876.         return 0;
  877.     }
  878.     return subcmd (Nfcmds, argc, argv, p);
  879. }
  880.  
  881.  
  882. /* display a list of <callsign,interface> pairs from the filter
  883.  * list.
  884.  */
  885. static int
  886. donfdump ()
  887. {
  888. int i, column = 1;
  889. struct nrnf_tab *fp;
  890. char buf[AXBUF];
  891.  
  892.     for (i = 0; i < NRNUMCHAINS; i++)
  893.         for (fp = Nrnf_tab[i]; fp != NULLNRNFTAB; fp = fp->next) {
  894.             pax25 (buf, fp->neighbor);
  895.             tprintf ("%-7s  %-8s  %-3d   ",
  896.                  buf, fp->iface->name, fp->quality);
  897.             if (column++ == 3) {
  898.                 if (tputc ('\n') == EOF)
  899.                     return 0;
  900.                 column = 1;
  901.             }
  902.         }
  903.  
  904.     if (column != 1)
  905.         tputc ('\n');
  906.  
  907.     return 0;
  908. }
  909.  
  910.  
  911. /* add an entry to the filter table */
  912. static int
  913. donfadd (int argc, char *argv[], void *p OPTIONAL)
  914. {
  915. struct iface *ifp;
  916. unsigned qual;
  917. char neighbor[AXALEN];
  918.  
  919.     /* format callsign */
  920.     if (setcall (neighbor, argv[1]) == -1) {
  921.         tputs ("bad neighbor callsign\n");
  922.         return -1;
  923.     }
  924.     /* find interface */
  925.     if ((ifp = FindNrIface (argv[2])) == NULLIF)
  926.         return -1;
  927.  
  928.     qual = (unsigned int) ifp->quality;    /* set default quality */
  929.  
  930.     if (argc > 3)
  931.         qual = (unsigned int) atoi (argv[3]);
  932.  
  933.     return nr_nfadd (neighbor, ifp, qual);
  934. }
  935.  
  936.  
  937. /* drop an entry from the filter table */
  938. static int
  939. donfdrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  940. {
  941. struct iface *ifp;
  942. char neighbor[AXALEN];
  943.  
  944.     /* format neighbor callsign */
  945.     if (setcall (neighbor, argv[1]) == -1) {
  946.         tputs ("bad neighbor callsign\n");
  947.         return -1;
  948.     }
  949.     /* find interface */
  950.     if ((ifp = FindNrIface (argv[2])) == NULLIF)
  951.         return -1;
  952.  
  953.     return nr_nfdrop (neighbor, ifp);
  954. }
  955.  
  956.  
  957. /* nodefilter mode subcommand */
  958. static int
  959. donfmode (int argc, char *argv[], void *p OPTIONAL)
  960. {
  961.     if (argc < 2) {
  962.         tputs ("filter mode is ");
  963.         switch (Nr_nfmode) {
  964.             case NRNF_NOFILTER:
  965.                 tputs ("none\n");
  966.                 break;
  967.             case NRNF_ACCEPT:
  968.                 tputs ("accept\n");
  969.                 break;
  970.             case NRNF_REJECT:
  971.                 tputs ("reject\n");
  972.                 break;
  973.             default:
  974.                 tputs ("some strange, unknown value\n");
  975.         }
  976.         return 0;
  977.     }
  978.     switch (argv[1][0]) {
  979.         case 'n':
  980.         case 'N':
  981.             Nr_nfmode = NRNF_NOFILTER;
  982.             break;
  983.         case 'a':
  984.         case 'A':
  985.             Nr_nfmode = NRNF_ACCEPT;
  986.             break;
  987.         case 'r':
  988.         case 'R':
  989.             Nr_nfmode = NRNF_REJECT;
  990.             break;
  991.         default:
  992.             tputs ("modes are: none accept reject\n");
  993.             return -1;
  994.     }
  995.  
  996.     return 0;
  997. }
  998.  
  999.  
  1000. /* netrom network packet time-to-live initializer */
  1001. static int
  1002. donrttl (int argc, char *argv[], void *p OPTIONAL)
  1003. {
  1004.     return setshort (&Nr_ttl, "Time to live", argc, argv);
  1005. }
  1006.  
  1007.  
  1008. /* show hidden (ie '#...') nodes or not */
  1009. static int
  1010. donrhidden (int argc, char *argv[], void *p OPTIONAL)
  1011. {
  1012.     return setbool (&Nr_hidden, "Hidden nodes", argc, argv);
  1013. }
  1014.  
  1015.  
  1016. /* allow automatic derating of netrom routes on link failure */
  1017. static int
  1018. donrderate (int argc, char *argv[], void *p OPTIONAL)
  1019. {
  1020.     return setbool (&Nr_derate, "Derate flag", argc, argv);
  1021. }
  1022.  
  1023.  
  1024. /* promiscuous acceptance of broadcasts */
  1025. static int
  1026. donrpromisc (int argc, char *argv[], void *p OPTIONAL)
  1027. {
  1028.     return setbool (&Nr_promisc, "Promiscuous flag", argc, argv);
  1029. }
  1030.  
  1031.  
  1032. #ifdef ALLSESSIONS
  1033. /* Initiate a NET/ROM transport connection */
  1034. static int
  1035. donrconnect (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  1036. {
  1037. struct nrroute_tab *np;
  1038. struct sockaddr_nr lsocket, fsocket;
  1039. char alias[AXBUF];
  1040. struct session *sp;
  1041. int split = 0;
  1042.  
  1043.     /*Make sure this comes from console - WG7J*/
  1044.     if (Curproc->input != Command->input)
  1045.         return 0;
  1046.  
  1047. #ifdef ALLSERV
  1048.     if (argv[0][0] == 's')
  1049.         split = 1;
  1050. #endif
  1051.  
  1052.     /* Get a session descriptor */
  1053.     if ((sp = newsession (argv[1], NRSESSION, split)) == NULLSESSION) {
  1054.         tputs (TooManySessions);
  1055.         return 1;
  1056.     }
  1057.     if ((sp->s = socket (AF_NETROM, SOCK_SEQPACKET, 0)) == -1) {
  1058.         tputs (Nosock);
  1059.         (void) keywait (NULLCHAR, 1);
  1060.         freesession (sp);
  1061.         return 1;
  1062.     }
  1063.     /* See if the requested destination is a known alias or call,
  1064.      * use it if it is.  Otherwize give an error message. - WG7J
  1065.      */
  1066.     (void) putalias (alias, argv[1], 0);
  1067.     (void) strupr (argv[1]);    /*make sure it's upper case*/
  1068.     if ((np = find_nrboth (alias, argv[1])) == NULLNRRTAB) {
  1069.         /*no such call or node alias*/
  1070.         tputs ("no such node\n\n");
  1071.         (void) keywait (NULLCHAR, 1);
  1072.         freesession (sp);
  1073.         return 1;
  1074.     }
  1075.     /* Setup the local side of the connection */
  1076.     lsocket.nr_family = AF_NETROM;
  1077.  
  1078.     /* Set up our local username, bind would use Mycall instead */
  1079.     memcpy (lsocket.nr_addr.user, Nr4user, AXALEN);
  1080.  
  1081.     /* Putting anything else than Nr_iface->hwaddr here will not work ! */
  1082.     memcpy (lsocket.nr_addr.node, Nr_iface->hwaddr, AXALEN);
  1083.  
  1084.     /* Now bind the socket to this */
  1085.     (void) bind (sp->s, (char *) &lsocket, sizeof (struct sockaddr_nr));
  1086.  
  1087.  
  1088.     /* Set up the remote side of the connection */
  1089.     fsocket.nr_family = AF_NETROM;
  1090.     memcpy (fsocket.nr_addr.user, np->call, AXALEN);
  1091.     memcpy (fsocket.nr_addr.node, np->call, AXALEN);
  1092.     fsocket.nr_family = AF_NETROM;
  1093.  
  1094.     return tel_connect (sp, (char *) &fsocket, sizeof (struct sockaddr_nr));
  1095. }
  1096.  
  1097. #endif
  1098.  
  1099.  
  1100. /* Reset a net/rom connection abruptly */
  1101. static int
  1102. donrreset (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  1103. {
  1104. struct nr4cb *cb;
  1105.  
  1106.     cb = (struct nr4cb *) htoi (argv[1]);
  1107.     if (!nr4valcb (cb)) {
  1108.         tputs (Notval);
  1109.         return 1;
  1110.     }
  1111.     reset_nr4 (cb);
  1112.     return 0;
  1113. }
  1114.  
  1115.  
  1116. /* Force retransmission on a net/rom connection */
  1117.  
  1118. static int
  1119. donrkick (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  1120. {
  1121. struct nr4cb *cb;
  1122.  
  1123.     cb = (struct nr4cb *) htoi (argv[1]);
  1124.     if (kick_nr4 (cb) == -1) {
  1125.         tputs (Notval);
  1126.         return 1;
  1127.     } else
  1128.         return 0;
  1129. }
  1130.  
  1131.  
  1132. /* netrom transport ACK delay timer */
  1133. static int
  1134. donracktime (int argc, char *argv[], void *p OPTIONAL)
  1135. {
  1136.     return setlong (&Nr4acktime, "Ack delay time (ms)", argc, argv);
  1137. }
  1138.  
  1139.  
  1140. /* netrom transport choke timeout */
  1141. static int
  1142. donrchoketime (int argc, char *argv[], void *p OPTIONAL)
  1143. {
  1144.     return setlong (&Nr4choketime, "Choke timeout (ms)", argc, argv);
  1145. }
  1146.  
  1147.  
  1148. /* netrom transport initial round trip time */
  1149.  
  1150. static int
  1151. donrirtt (int argc, char *argv[], void *p OPTIONAL)
  1152. {
  1153.     return setlong (&Nr4irtt, "Initial RTT (ms)", argc, argv);
  1154. }
  1155.  
  1156.  
  1157. /* netrom transport receive queue length limit.  This is the */
  1158. /* threshhold at which we will CHOKE the sender. */
  1159.  
  1160. static int
  1161. donrqlimit (int argc, char *argv[], void *p OPTIONAL)
  1162. {
  1163.     return setshort (&Nr4qlimit, "Queue limit (bytes)", argc, argv);
  1164. }
  1165.  
  1166.  
  1167. /* Display or change our NET/ROM username */
  1168. static int
  1169. donruser (int argc, char *argv[], void *p OPTIONAL)
  1170. {
  1171. char buf[AXBUF];
  1172.  
  1173.     if (argc < 2) {
  1174.         pax25 (buf, Nr4user);
  1175.         tprintf ("%s\n", buf);
  1176.         return 0;
  1177.     }
  1178.     if (setcall (Nr4user, argv[1]) == -1)
  1179.         return -1;
  1180.     Nr4user[ALEN] |= E;
  1181.     return 0;
  1182. }
  1183.  
  1184.  
  1185. /* netrom transport maximum window.  This is the largest send and */
  1186. /* receive window we may negotiate */
  1187.  
  1188. static int
  1189. donrwindow (int argc, char *argv[], void *p OPTIONAL)
  1190. {
  1191.     return setshort (&Nr4window, "Window (frames)", argc, argv);
  1192. }
  1193.  
  1194.  
  1195. /* netrom transport maximum retries.  This is used in connect and */
  1196. /* disconnect attempts; I haven't decided what to do about actual */
  1197. /* data retries yet. */
  1198.  
  1199. static int
  1200. donrretries (int argc, char *argv[], void *p OPTIONAL)
  1201. {
  1202.     return setshort (&Nr4retries, "Retry limit", argc, argv);
  1203. }
  1204.  
  1205.  
  1206. /* Display the status of NET/ROM connections */
  1207.  
  1208. int
  1209. donrstatus (int argc, char *argv[], void *p OPTIONAL)
  1210. {
  1211. int i;
  1212. struct nr4cb *cb;
  1213. char luser[AXBUF], ruser[AXBUF], node[AXBUF];
  1214.  
  1215.     if (argc < 2) {
  1216. #ifdef UNIX
  1217.         tputs ("&NCB     Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1218. #else
  1219.         tputs ("&NCB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1220. #endif
  1221.         for (i = 0; i < NR4MAXCIRC; i++) {
  1222.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1223.                 continue;
  1224.             pax25 (luser, cb->local.user);
  1225.             pax25 (ruser, cb->remote.user);
  1226.             pax25 (node, cb->remote.node);
  1227. #ifdef UNIX
  1228.             if (tprintf ("%8.8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1229. #else
  1230.             if (tprintf ("%4.4x   %3d %5d %5d %9s  %9s %-9s %s\n",
  1231. #endif
  1232.                 (uint32) cb, cb->nbuffered, len_q (cb->txq),
  1233.                      len_p (cb->rxq), luser, ruser, node,
  1234.                      Nr4states[cb->state]) == EOF)
  1235.                 break;
  1236.         }
  1237.         return 0;
  1238.     }
  1239.     cb = (struct nr4cb *) htoi (argv[1]);
  1240.     if (!nr4valcb (cb)) {
  1241.         tputs (Notval);
  1242.         return 1;
  1243.     }
  1244.     donrdump (cb);
  1245.     return 0;
  1246. }
  1247.  
  1248.  
  1249. /* Dump one control block */
  1250.  
  1251. void
  1252. donrdump (struct nr4cb *cb)
  1253. {
  1254. char luser[AXBUF], ruser[AXBUF], node[AXBUF];
  1255. unsigned seq;
  1256. struct nr4txbuf *b;
  1257. struct timer *t;
  1258.  
  1259.     pax25 (luser, cb->local.user);
  1260.     pax25 (ruser, cb->remote.user);
  1261.     pax25 (node, cb->remote.node);
  1262.  
  1263.     tprintf ("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1264.          luser, cb->mynum, cb->myid, ruser, node,
  1265.          cb->yournum, cb->yourid, Nr4states[cb->state]);
  1266.  
  1267.     tprintf ("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1268.          cb->window, uchar (cb->rxpected), uchar (cb->rxpastwin),
  1269.          len_p (cb->rxq), cb->qfull ? "RxCHOKED" : "");
  1270.  
  1271.     tprintf (" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1272.            cb->nbuffered, uchar (cb->ackxpected), uchar (cb->nextosend),
  1273.          len_q (cb->txq), cb->choked ? "TxCHOKED" : "");
  1274.  
  1275.     tputs ("TACK: ");
  1276.     if (run_timer (&cb->tack))
  1277.         tprintf ("%lu", read_timer (&cb->tack));
  1278.     else
  1279.         tputs ("stop");
  1280.     tprintf ("/%lu ms; ", dur_timer (&cb->tack));
  1281.  
  1282.     tputs ("TChoke: ");
  1283.     if (run_timer (&cb->tchoke))
  1284.         tprintf ("%lu", read_timer (&cb->tchoke));
  1285.     else
  1286.         tputs ("stop");
  1287.     tprintf ("/%lu ms; ", dur_timer (&cb->tchoke));
  1288.  
  1289.     tputs ("TCD: ");
  1290.     if (run_timer (&cb->tcd))
  1291.         tprintf ("%lu", read_timer (&cb->tcd));
  1292.     else
  1293. #ifndef NR4TDISC
  1294.         tputs ("stop");
  1295.     tprintf ("/%lu ms", dur_timer (&cb->tcd));
  1296. #else
  1297.         tputs ("stop");
  1298.     tprintf ("/%lu ms; ", dur_timer (&cb->tcd));
  1299.  
  1300.     tputs ("TDisc: ");
  1301.     if (run_timer (&cb->tdisc))
  1302.         tprintf ("%lu", (read_timer (&cb->tdisc) / 1000L));
  1303.     else
  1304.         tputs ("stop");
  1305.     tprintf ("/%lu", (dur_timer (&cb->tdisc) / 1000L));
  1306. #endif
  1307.  
  1308.     if (run_timer (&cb->tcd))
  1309.         tprintf ("; Tries: %u\n", cb->cdtries);
  1310.     else
  1311.         tputc ('\n');
  1312.  
  1313.     tprintf ("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1314.          cb->blevel, cb->srtt, cb->mdev);
  1315.  
  1316.     /* If we are connected and the send window is open, display */
  1317.     /* the status of all the buffers and their timers */
  1318.  
  1319.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1320.  
  1321.         tputs ("TxBuffers:  Seq  Size  Tries  Timer\n");
  1322.  
  1323.         for (seq = cb->ackxpected;
  1324.              nr4between ((unsigned) cb->ackxpected, seq, (unsigned) cb->nextosend);
  1325.              seq = (seq + 1) & NR4SEQMASK) {
  1326.  
  1327.             b = &cb->txbufs[seq % cb->window];
  1328.             t = &b->tretry;
  1329.  
  1330.             if (tprintf ("            %3u   %3d  %5d  %lu/%lu\n",
  1331.                      seq, len_p (b->data), b->retries + 1,
  1332.                      read_timer (t), dur_timer (t))
  1333.                 == EOF)
  1334.                 break;
  1335.         }
  1336.  
  1337.     }
  1338. }
  1339.  
  1340.  
  1341. /* netrom timers type - linear v exponential */
  1342. static int
  1343. donrtype (int argc, char *argv[], void *p OPTIONAL)
  1344. {
  1345.     if (argc < 2) {
  1346.         tprintf ("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential");
  1347.         return 0;
  1348.     }
  1349.     switch (argv[1][0]) {
  1350.         case 'l':
  1351.         case 'L':
  1352.             Nr_timertype = 1;
  1353.             break;
  1354.         case 'e':
  1355.         case 'E':
  1356.             Nr_timertype = 0;
  1357.             break;
  1358.         default:
  1359.             tputs ("use: netrom timertype [linear|exponential]\n");
  1360.             return -1;
  1361.     }
  1362.  
  1363.     return 0;
  1364. }
  1365.  
  1366.  
  1367. static int
  1368. dominquality (int argc, char *argv[], void *p OPTIONAL)
  1369. {
  1370. unsigned val;
  1371.  
  1372.     if (argc < 2) {
  1373.         tprintf ("%u\n", Nr_autofloor);
  1374.         return 0;
  1375.     }
  1376.     val = (unsigned int) atoi (argv[1]);
  1377.  
  1378.     if (val == 0 || val > 255) {
  1379.         tputs ("The minimum acceptable quality must be 1 to 255\n");
  1380.         return 1;
  1381.     }
  1382.     Nr_autofloor = val;
  1383.  
  1384.     return 0;
  1385. }
  1386.  
  1387.  
  1388. /* Fixed and now functional, 920317 WG7J */
  1389. int
  1390. donrload (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  1391. {
  1392. char buff[255];
  1393. FILE *fn;
  1394. time_t now, prev;
  1395. #ifdef notdef
  1396. long t1, t2;
  1397. int j;
  1398. #endif
  1399. int quality, obso;
  1400. int permanent, record;
  1401. struct iface *ifp;
  1402. char alias[12], dest[12], iface[12], neighbor[12], type[3], *ptr;
  1403. char destalias[ALEN + 1];    /*alias in 'alias form'*/
  1404. char destcall[AXALEN];    /*in callsign (ie shifted) form */
  1405. char destneighbor[AXALEN];
  1406.  
  1407.     if (Nr_iface == NULLIF) {
  1408.         tputs ("Attach netrom interface first\n");
  1409.         return 1;
  1410.     }
  1411.     if ((fn = fopen (Netromfile, READ_TEXT)) == NULLFILE) {
  1412.         tputs("Can't open netrom save file!\n");
  1413.         return 1;
  1414.     }
  1415.     if (fgets (buff, sizeof (buff), fn) == NULLCHAR) {    /* read the timestamp */
  1416.         (void) fclose (fn);
  1417.         return 1;
  1418.     }
  1419.     if ((strncmp (buff, "time = ", 7)) != 0) {
  1420.         tputs("Wrong node file content\n");
  1421.         (void) fclose (fn);
  1422.         return 1;
  1423.     }
  1424.     (void) time (&now);
  1425.     sscanf (buff, "time =%ld", &prev);
  1426.     if (prev >= now) {
  1427.         (void) fclose (fn);
  1428.         return 1;
  1429.     }
  1430. #ifdef notdef
  1431.     t1 = now - prev;
  1432.     t2 = dur_timer (&Obsotimer) / 1000L;
  1433.     j = t1 / t2;        /* recalculate obsolete count */
  1434.     tprintf ("%ld seconds are past ( %d obsolete scans)\n", t1, j);
  1435. #endif
  1436.  
  1437.     while (fgets (buff, sizeof (buff), fn) != NULLCHAR) {
  1438.         if ((ptr = strchr (buff, ':')) == 0) {
  1439.             sscanf (buff, "%s%s%i%i%s%s"
  1440.                  ,dest, type, &quality, &obso, iface, neighbor);
  1441.             alias[0] = '\0';
  1442.         } else {
  1443.             *ptr = ' ';
  1444.             sscanf (buff, "%s%s%s%i%i%s%s"
  1445.                 ,alias, dest, type, &quality, &obso, iface, neighbor);
  1446.         }
  1447.         /*Set and check calls / alias - WG7J */
  1448.         if (setcall (destcall, dest) == -1)
  1449.             continue;
  1450.  
  1451.         if (setcall (destneighbor, neighbor) == -1)
  1452.             continue;
  1453.  
  1454.         if (putalias (destalias, alias, 1) == -1)
  1455.             continue;
  1456.  
  1457.         /* find interface */
  1458.         if ((ifp = if_lookup (iface)) == NULLIF)
  1459.             continue;
  1460.  
  1461.         /* Is it a netrom interface ? */
  1462.         if (!(ifp->flags & IS_NR_IFACE))
  1463.             continue;
  1464.  
  1465.         /* get and check quality value */
  1466.         if (quality > 255 || (unsigned) quality < Nr_autofloor)
  1467.             continue;
  1468.  
  1469.         /* Check the type of route - WG7J */
  1470.         permanent = record = 0;
  1471.         if (strchr (type, 'P') != NULLCHAR)
  1472.             permanent = 1;
  1473.         else {
  1474.             if (strchr (type, 'R') != NULLCHAR)
  1475.                 record = 1;
  1476.         }
  1477.         (void) nr_routeadd (destalias, destcall, ifp, (unsigned) quality, destneighbor, \
  1478.                  (unsigned) permanent, (unsigned) record);
  1479.     }
  1480.     (void) fclose (fn);
  1481.     return 0;
  1482. }
  1483.  
  1484.  
  1485. int
  1486. donrsave (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  1487. {
  1488. register struct nrroute_tab *rp;
  1489. register struct nr_bind *bp;
  1490. register struct nrnbr_tab *np;
  1491. char neighbor[AXBUF];
  1492. register int i;
  1493. char buf[16];
  1494. char *cp;
  1495. FILE *fn;
  1496. time_t now;
  1497.  
  1498.     if ((fn = fopen (Netromfile, "w+")) == NULLFILE) {
  1499.         tputs ("Can't write netrom save file!\n");
  1500.         return 1;
  1501.     }
  1502.     (void) time (&now);
  1503.     fprintf (fn, "time = %ld\n", now);
  1504.     for (i = 0; i < NRNUMCHAINS; i++) {
  1505.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  1506.             strncpy (buf, rp->alias, 16);
  1507.             /* remove trailing spaces */
  1508.             if ((cp = strchr (buf, ' ')) == NULLCHAR)
  1509.                 cp = &buf[strlen (buf)];
  1510.             if (cp != buf)    /* don't include colon for null alias */
  1511.                 *cp++ = ':';
  1512.             for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1513.                 pax25 (cp, rp->call);
  1514.                 fprintf (fn, "%-16s  ", buf);
  1515.                 np = bp->via;
  1516.                 if (fprintf (fn, "%1s %3d  %3d  %-8s  %s\n",
  1517.                       (bp->flags & NRB_PERMANENT ? "P" :
  1518.                       bp->flags & NRB_RECORDED ? "R" : "X"),
  1519.                          bp->quality, bp->obsocnt,
  1520.                          np->iface->name,
  1521.                      pax25 (neighbor, np->call)) == EOF)
  1522.                     break;
  1523.             }
  1524.         }
  1525.     }
  1526.     (void) fclose (fn);
  1527.     return 0;
  1528. }
  1529.  
  1530. #endif /* NETROM */
  1531.